red=\e[1;31m
NC=\e[0m


ifeq ("$(origin J)", "command line")
  JOBS = -j$(J)
endif
ifndef JOBS
  JOBS = -j$(shell nproc)
endif
export JOBS

ifeq ("$(origin D)", "command line")
  DEBUG = -S -s
endif

ifeq ("$(origin CONF)", "command line")
  $(shell echo CONF=$(CONF)>.last_conf)
endif

-include .last_conf
export TOP_DIR := $(shell pwd)
export CONFIG_DIR=$(TOP_DIR)/configs
export BUILD_DIR := $(TOP_DIR)/output/$(CONF)
export BUILD_SCRIPTS := $(TOP_DIR)/build

include $(BUILD_SCRIPTS)/parse.mk


ADD_PATH := :$(EXEC_PATH)
TMP_PATH := $(addsuffix $(ADD_PATH), $(PATH))
export PATH=$(TMP_PATH)


.PHONY: all
all: check_arg uboot tpl linux opensbi buildroot image-final

.PHONY: defconfig
defconfig: $(CONFIG_DIR)/$(CONF)
	@cp configs/$(CONF) $(TOP_DIR)/.config; \
	touch $@

.PHONY: buildroot
buildroot: defconfig
	@export CROSS_COMPILE=$(CC_PREFIX); export ARCH=riscv; \
	cd $(BUILDROOT_SRC_PATH); \
	make CONF=$(BUILDROOT_DEFCONFIG) BRW_BUILD_DIR=$(BUILDROOT_BUILD_DIR) BR2_TOOLCHAIN_EXTERNAL_PATH=$(EXEC_PATH)/../ BR2_TOOLCHAIN_EXTERNAL_CUSTOM_PREFIX=$(CC_PREFIX) || exit $?; \
	cd -

.PHONY: buildroot-menuconfig
buildroot-menuconfig: defconfig
	@export CROSS_COMPILE=$(CC_PREFIX); export ARCH=riscv; \
	cd $(BUILDROOT_SRC_PATH); \
	make CONF=$(BUILDROOT_DEFCONFIG) BRW_BUILD_DIR=$(BUILDROOT_BUILD_DIR) BR2_TOOLCHAIN_EXTERNAL_PATH=$(EXEC_PATH)/../ BR2_TOOLCHAIN_EXTERNAL_CUSTOM_PREFIX=$(CC_PREFIX) menuconfig; \
	cd -

.PHONY: buildroot-rebuild
buildroot-rebuild: defconfig
	@export CROSS_COMPILE=$(CC_PREFIX); export ARCH=riscv; \
	cd $(BUILDROOT_SRC_PATH); \
	make CONF=$(BUILDROOT_DEFCONFIG) BRW_BUILD_DIR=$(BUILDROOT_BUILD_DIR) BR2_TOOLCHAIN_EXTERNAL_PATH=$(EXEC_PATH)/../ BR2_TOOLCHAIN_EXTERNAL_CUSTOM_PREFIX=$(CC_PREFIX) build; \
	cd -

.PHONY: buildroot-savedefconfig
buildroot-savedefconfig: defconfig
	@export CROSS_COMPILE=$(CC_PREFIX); export ARCH=riscv; \
	cd $(BUILDROOT_SRC_PATH); \
	make CONF=$(BUILDROOT_DEFCONFIG) BRW_BUILD_DIR=$(BUILDROOT_BUILD_DIR) BR2_TOOLCHAIN_EXTERNAL_PATH=$(EXEC_PATH)/../ BR2_TOOLCHAIN_EXTERNAL_CUSTOM_PREFIX=$(CC_PREFIX) savedefconfig; \
	cd -

.PHONY: buildroot-clean
buildroot-clean: defconfig
	@export CROSS_COMPILE=$(CC_PREFIX); export ARCH=riscv; \
	cd $(BUILDROOT_SRC_PATH); \
	make CONF=$(BUILDROOT_DEFCONFIG) BRW_BUILD_DIR=$(BUILDROOT_BUILD_DIR) BR2_TOOLCHAIN_EXTERNAL_PATH=$(EXEC_PATH)/../ BR2_TOOLCHAIN_EXTERNAL_CUSTOM_PREFIX=$(CC_PREFIX) clean; \
	cd -

.PHONY: opensbi
opensbi: defconfig
	@echo "build opensbi"
	@export CROSS_COMPILE=$(CC_PREFIX); export ARCH=riscv; \
	cd $(OPENSBI_SRC_PATH); \
	make PLATFORM=$(OPENSBI_PLATFORM) all O=$(OPENSBI_BUILD_DIR) $(JOBS) || exit $?; \
	cd -

.PHONY: opensbi-menuconfig
opensbi-menuconfig: defconfig
	@echo "opensbi menuconfig"
	@export CROSS_COMPILE=$(CC_PREFIX); export ARCH=riscv; \
	cd $(OPENSBI_SRC_PATH); \
	make PLATFORM=$(OPENSBI_PLATFORM) menuconfig O=$(OPENSBI_BUILD_DIR) $(JOBS) || exit $?; \
	cd -

.PHONY: opensbi-savedefconfig
opensbi-savedefconfig: defconfig
	@echo "opensbi savedefconfig"
	@export CROSS_COMPILE=$(CC_PREFIX); export ARCH=riscv; \
	cd $(OPENSBI_SRC_PATH); \
	make PLATFORM=$(OPENSBI_PLATFORM) savedefconfig O=$(OPENSBI_BUILD_DIR) $(JOBS) || exit $?; \
	cd -

.PHONY: opensbi-clean
opensbi-clean: defconfig
	@echo "clean opensbi"
	@export CROSS_COMPILE=$(CC_PREFIX);export ARCH=riscv; \
	cd $(OPENSBI_BUILD_DIR); \
	rm -rf ./*; \
	cd -

.PHONY: uboot
uboot: defconfig
	@echo "build uboot"
	@export CROSS_COMPILE=$(CC_PREFIX);export ARCH=riscv; \
	cd $(UBOOT_SRC_PATH); \
	make $(UBOOT_DEFCONFIG) O=$(UBOOT_BUILD_DIR) || exit $?; make -C $(UBOOT_BUILD_DIR) $(JOBS) || exit $?; \
	cd -

.PHONY: uboot-menuconfig
uboot-menuconfig: defconfig
	@export CROSS_COMPILE=$(CC_PREFIX);export ARCH=riscv; \
	cd $(UBOOT_SRC_PATH); \
	make -C $(UBOOT_BUILD_DIR) menuconfig; \
	cd -

.PHONY: uboot-rebuild
uboot-rebuild: defconfig
	@export CROSS_COMPILE=$(CC_PREFIX);export ARCH=riscv; \
	make -C $(UBOOT_BUILD_DIR)  $(JOBS) || exit $?; \
	cd -

.PHONY: uboot-savedefconfig
uboot-savedefconfig: defconfig
	@export CROSS_COMPILE=$(CC_PREFIX);export ARCH=riscv; \
	cd $(UBOOT_BUILD_DIR); \
	make -C $(UBOOT_BUILD_DIR) savedefconfig; \
	cd -

.PHONY: uboot-clean
uboot-clean: defconfig
	@export CROSS_COMPILE=$(CC_PREFIX);export ARCH=riscv; \
	make -C $(UBOOT_BUILD_DIR) clean; \
	cd -


.PHONY: tpl
tpl: defconfig
	@echo "build uboot tpl"
	@export CROSS_COMPILE=$(CC_PREFIX);export ARCH=riscv; \
	cd $(UBOOT_SRC_PATH); \
	make $(UBOOT_TPL_DEFCONFIG) O=$(UBOOT_TPL_BUILD_DIR) || exit $?; make -C $(UBOOT_TPL_BUILD_DIR) $(JOBS) || exit $?; \
	cd -

.PHONY: tpl-menuconfig
tpl-menuconfig: defconfig
	@export CROSS_COMPILE=$(CC_PREFIX);export ARCH=riscv; \
	cd $(UBOOT_SRC_PATH); \
	make -C $(UBOOT_TPL_BUILD_DIR) menuconfig; \
	cd -

.PHONY: tpl-rebuild
tpl-rebuild: defconfig
	@export CROSS_COMPILE=$(CC_PREFIX);export ARCH=riscv; \
	make -C $(UBOOT_TPL_BUILD_DIR)  $(JOBS) || exit $?; \
	cd -

.PHONY: tpl-savedefconfig
tpl-savedefconfig: defconfig
	@export CROSS_COMPILE=$(CC_PREFIX);export ARCH=riscv; \
	cd $(UBOOT_TPL_BUILD_DIR); \
	make -C $(UBOOT_TPL_BUILD_DIR) savedefconfig; \
	cd -

.PHONY: tpl-clean
tpl-clean: defconfig
	@export CROSS_COMPILE=$(CC_PREFIX);export ARCH=riscv; \
	make -C $(UBOOT_TPL_BUILD_DIR) clean; \
	cd -

.PHONY: linux
linux: defconfig
	@echo "build linux kernel"
	@export CROSS_COMPILE=$(CC_PREFIX);export ARCH=riscv; \
	cd $(LINUX_SRC_PATH); \
	make $(LINUX_DEFCONFIG) O=$(LINUX_BUILD_DIR)  $(JOBS) || exit $?; \
	make O=$(LINUX_BUILD_DIR)  $(JOBS) || exit $?; \
	make O=$(LINUX_BUILD_DIR) modules_install INSTALL_MOD_PATH=$(LINUX_BUILD_DIR)/rootfs/ $(JOBS) || exit $?; \
	cd -

.PHONY: linux-menuconfig
linux-menuconfig: defconfig
	@export CROSS_COMPILE=$(CC_PREFIX);export ARCH=riscv; \
	cd $(LINUX_SRC_PATH); \
	make O=$(LINUX_BUILD_DIR) menuconfig $(JOBS); \
	cd -

.PHONY: linux-rebuild
linux-rebuild: defconfig
	@export CROSS_COMPILE=$(CC_PREFIX);export ARCH=riscv; \
	make -C $(LINUX_BUILD_DIR) $(JOBS) || exit $?; \
	make -C $(LINUX_BUILD_DIR) modules_install INSTALL_MOD_PATH=$(LINUX_BUILD_DIR)/rootfs/ $(JOBS) || exit $?; \
	cd -

.PHONY: linux-savedefconfig
linux-savedefconfig: defconfig
	@export CROSS_COMPILE=$(CC_PREFIX);export ARCH=riscv; \
	cd $(LINUX_SRC_PATH); \
	make O=$(LINUX_BUILD_DIR) savedefconfig; \
	cd -

.PHONY: linux-clean
linux-clean: defconfig
	@export CROSS_COMPILE=$(CC_PREFIX);export ARCH=riscv; \
	cd $(LINUX_SRC_PATH); \
	make O=$(LINUX_BUILD_DIR) clean; \
	cd -

check_arg:check_toolchain check_output_dir

check_toolchain:
	@echo "$(EXEC_PATH)/$(CC_PREFIX)gcc"
	@if  [ ! -f  $(EXEC_PATH)/$(CC_PREFIX)gcc ]; then \
		 echo "no toolchain"; exit 1;  \
	fi

check_output_dir:
	@mkdir -p $(BUILDROOT_BUILD_DIR); \
	mkdir -p $(OPENSBI_BUILD_DIR); \
	mkdir -p $(UBOOT_BUILD_DIR); \
	mkdir -p $(LINUX_BUILD_DIR); \
	mkdir -p $(QEMU_BUILD_DIR); \
	mkdir -p $(UBOOT_TPL_BUILD_DIR)

.PHONY: qemu
qemu:
	@echo "build qemu"
	cd $(QEMU_SRC_PATH); \
	./configure --prefix=$(QEMU_BUILD_DIR) \
	--target-list=riscv64-softmmu \
	--enable-gtk \
	--enable-virtfs \
	--disable-gio \
	--enable-plugins \
	--audio-drv-list=pa,alsa,sdl,oss; \
	make $(JOBS); \
	make install; \
	cd -

.PHONY: image-final
image-final:
	@echo "build image"
	set -e; \
	bash $(CONFIG_GEN_IMG_SCRIPT)

.PHONY: docker
docker:
	@container_name=$(shell whoami); \
	if docker ps -a --format '{{.Names}}' | grep -q $$container_name; then \
		docker start $$container_name; \
		docker exec -it $$container_name /bin/bash; \
	else \
		echo "---> docker run"; \
		docker run --name $$container_name -u root -it -v /home/$$container_name/:/home/$$container_name -v $(PWD)/toolchain:/opt/toolchain -w /home/$$container_name apsilicon-sdk /bin/bash; \
	fi

.PHONY: a-qemu
a-qemu:
	$(QEMU_BUILD_DIR)/bin/qemu-system-riscv64 -M aurora,mask-rom-path="$(TOP_DIR)/maskrom/mask_rom.bin" \
	-m 1G -smp 1 -nographic --parallel none \
	-global aurora-syscon.boot-cfg="sd" \
	-drive if=sd,format=raw,file=$(BUILD_DIR)/images/sdcard.img,id=sd0 \
	$(DEBUG)

.PHONY: a-spi
a-spi:
	$(QEMU_BUILD_DIR)/bin/qemu-system-riscv64 -M aurora,mask-rom-path="$(TOP_DIR)/maskrom/build/mask_rom.bin" \
	-m 1G -smp 1 -nographic --parallel none \
	-global aurora-syscon.boot-cfg="spinor" \
	-drive if=mtd,bus=0,unit=0,format=raw,file=$(BUILD_DIR)/images/spinor.img,id=mtd1 \
	-global virtio-mmio.force-legacy=false \
	$(DEBUG)


.PHONY: clean
clean:
	@rm -rf defconfig
	@rm -rf $(BUILD_DIR)

# List the defconfig files
define list-defconfigs
	@first=true; \
	for defconfig in $(1)/configs/*_defconfig; do \
		[ -f "$${defconfig}" ] || continue; \
		if $${first}; then \
			printf "configs:\n"; \
			first=false; \
		fi; \
		defconfig="$${defconfig##*/}"; \
		printf "  %-35s - Build for %s\n" "$${defconfig}" "$${defconfig%_defconfig}"; \
	done; \
	$${first} || printf "\n"
endef

.PHONY: list
list:
	$(call list-defconfigs,$(TOP_DIR))

help:
	@echo "Usage:"
	@echo "make CONF=xxx_defconfig defconfig --- First run command, xxx from make list";
	@echo "make list                         --- List all available defconfig";
	@echo "make buildroot                    --- Build buildroot with defconfig";
	@echo "make buildroot-menuconfig         --- Menuconfig for buildroot, select save will save to output/buildroot/.config";
	@echo "make buildroot-rebuild            --- Rebuild buildroot";
	@echo "make buildroot-savedefconfig      --- Save buildroot configuration to buildroot/configs/xx_defconfig";
	@echo "make buildroot-clean              --- Clean the buildroot build directory, after clean, run make buildroot-rebuild will fail because the build cirectory is not exist. Run make buildroot to build";
	@echo "make uboot                        --- Build uboot";
	@echo "make uboot-menuconfig             --- Menuconfig for uboot, select save will save to output/uboot/.config";
	@echo "make uboot-rebuild                --- Rebuild uboot";
	@echo "make uboot-savedefconfig          --- Save uboot minil configuration to output/uboot/defconfig";
	@echo "make uboot-clean                  --- Carry out clean in uboot build directory"
	@echo "make opensbi                      --- Build opensbi";
	@echo "make opensbi-clean                --- Carry out clean in opensbi build directory";
	@echo "make opensbi-menuconfig           --- Menuconfig for opensbi";
	@echo "make opensbi-savedefconfig        --- Save opensbi mini configuration to opensbi/platform/xxx/xxx/kconfig/defconfig";
	@echo "make linux                        --- build linux kernel";
	@echo "make linux-menuconfig             --- Menuconfig for linux kernel, select save will save to output/linux/.config";
	@echo "make linux-rebuild                --- Rebuild linux kernel";
	@echo "make linux-savedefconfig          --- Save linux kernel configuration to output/linux/defconfig";
	@echo "make linux-clean                  --- Carry out clean in linux kernel build directory";
	@echo "make docker                       --- Login docker";
	@echo "make image-final                  --- Build and tar image";
	@echo "make a-spi                        --- Emulate kernel running for apsilicon board";

